package cn.donting.jme.core.state;

import cn.donting.jme.EditorContent;
import cn.donting.jme.JmeApplication;
import cn.donting.jme.core.post.DefSceneProcessor;
import cn.donting.jme.editor.scene.SceneCamera;
import cn.donting.jme.ioc.Bean;
import cn.donting.jme.utile.MathUtil;
import com.jme3.app.state.AppStateManager;
import com.jme3.material.Material;
import com.jme3.material.Materials;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Line;
import com.jme3.shader.ShaderUtils;
import com.jme3.shadow.ShadowUtil;

/**
 * 相机
 */
@Bean
public class ShowCameraMatrixViewState extends AbstractEditorAppState implements DefSceneProcessor {
    private SceneCamera sceneCamera;

    private Node node;
    private Geometry leftTopLineGeometry;
    private Geometry leftBottomLineGeometry;

    private Geometry rightTopLineGeometry;
    private Geometry rightBottomLineGeometry;

    private float lineLength;
    private float fovY;

    private float maxLineLength = 3;

    private float cameraViewSizeW = 150;
    private float cameraViewSizeH = 100;

    private ViewPort sceneCameraView;
    private Camera camera;

    @Override
    public void initialize(AppStateManager stateManager, JmeApplication app) {
        node = new Node("CameraMatrixViewNode");
        EditorContent.getJmeApplication().getEditorNode().attachChild(node);
        Material material = new Material(app.getAssetManager(), Materials.UNSHADED);
        material.setColor("Color", ColorRGBA.Yellow);
        lineLength = 1;
        Line line = new Line(new Vector3f(0, 0, 0), new Vector3f(0, 0, lineLength));
        leftTopLineGeometry = new Geometry("leftTopLineGeometry");
        leftTopLineGeometry.setMesh(line);
        leftTopLineGeometry.setMaterial(material);
        leftBottomLineGeometry = new Geometry("leftBottomLineGeometry");
        leftBottomLineGeometry.setMesh(line);
        leftBottomLineGeometry.setMaterial(material);
        rightTopLineGeometry = new Geometry("rightTopLineGeometry");
        rightTopLineGeometry.setMesh(line);
        rightTopLineGeometry.setMaterial(material);
        rightBottomLineGeometry = new Geometry("rightBottomLineGeometry");
        rightBottomLineGeometry.setMesh(line);
        rightBottomLineGeometry.setMaterial(material);

        node.attachChild(leftTopLineGeometry);
        node.attachChild(leftBottomLineGeometry);
        node.attachChild(rightTopLineGeometry);
        node.attachChild(rightBottomLineGeometry);


        camera = new Camera(app.getEditorCamera().getWidth(), app.getEditorCamera().getHeight());
        camera.setName("SceneCameraView");
        camera.setFrustumPerspective(45f, (float) camera.getWidth() / camera.getHeight(), 1f, 1000f);
        camera.setLocation(new Vector3f(0f, 0f, 0f));
        camera.lookAt(new Vector3f(0f, 0f, -5f), Vector3f.UNIT_Y);
        camera.setViewPort(1f - cameraViewSizeW / camera.getWidth(), 1f, 0, 1f - cameraViewSizeH / camera.getHeight());
        camera.resize(camera.getWidth(), camera.getHeight(), true);

        RenderManager renderManager = app.getRenderManager();
        sceneCameraView = renderManager.createPostView("SceneCameraView", camera);
        sceneCameraView.setEnabled(false);
        sceneCameraView.attachScene(EditorContent.getJmeApplication().getSceneNode());
        sceneCameraView.setClearFlags(true, true, true);
        sceneCameraView.addProcessor(this);
    }


    public void setSceneCamera(SceneCamera sceneCamera) {
        this.sceneCamera = sceneCamera;
        if (sceneCamera == null) {
            sceneCameraView.setEnabled(false);
        }else {
            sceneCameraView.setEnabled(true);
        }
    }

    @Override
    public void update(float tpf) {
        if (sceneCamera == null) {
            if (node.getParent() != null) {
                EditorContent.getJmeApplication().getEditorNode().detachChild(node);
            }
            return;
        } else {
            if (node.getParent() == null) {
                EditorContent.getJmeApplication().getEditorNode().attachChild(node);
            }
        }
        camera.setLocation(sceneCamera.getCamera().getLocation());
        camera.setRotation(sceneCamera.getCamera().getRotation());
        sceneCameraView.setClearFlags(true, sceneCamera.isViewPortClearDepth(), sceneCamera.isViewPortClearStencil());
        sceneCameraView.setBackgroundColor(sceneCamera.getViewPortBackColor());



        node.setLocalTranslation(sceneCamera.getCamera().getLocation());
        node.setLocalRotation(sceneCamera.getCamera().getRotation());
        float lineLength = Math.min(sceneCamera.getFar(), maxLineLength);
        if (lineLength != this.lineLength) {
            this.lineLength = lineLength;
            Line line = new Line(new Vector3f(0, 0, 0), new Vector3f(0, 0, this.lineLength));
            leftTopLineGeometry.setMesh(line);
            leftBottomLineGeometry.setMesh(line);
            rightTopLineGeometry.setMesh(line);
            rightBottomLineGeometry.setMesh(line);
        }
        if (sceneCamera.getFovY() != fovY) {
            fovY = sceneCamera.getFovY();
            float angle = fovY / 2;
            float v = MathUtil.angleToRadian(angle);
            Quaternion quaternion = new Quaternion();
            quaternion.fromAngles(-v, 0, -v);
            leftTopLineGeometry.setLocalRotation(quaternion);
            quaternion = new Quaternion();
            quaternion.fromAngles(-v, 0, v);
            rightTopLineGeometry.setLocalRotation(quaternion);

            quaternion = new Quaternion();
            quaternion.fromAngles(v, 0, -v);
            leftBottomLineGeometry.setLocalRotation(quaternion);

            quaternion = new Quaternion();
            quaternion.fromAngles(v, 0, v);
            rightBottomLineGeometry.setLocalRotation(quaternion);
        }
    }


    @Override
    public void reshape(ViewPort vp, int w, int h) {
        camera.setFrustumPerspective(45f, (float) w / h, 1f, 1000f);
        camera.setViewPort(1f - cameraViewSizeW / camera.getWidth(), 1f, 0,  cameraViewSizeH / camera.getHeight());

        //用于重置相机大小，防止变形
        camera.resize(w,h,true);
    }
}
